from flask import current_app
from flask_restx import Namespace, Resource, fields
from flask_jwt_extended import (
    create_access_token,
    create_refresh_token,
    get_jwt_identity,
    jwt_required,
)
from flask_security.utils import verify_password

from ..models import User

ns = Namespace("auth", description="身份认证相关接口")

login_model = ns.model(
    "LoginPayload",  # 登录请求模型名称
    {
        "email": fields.String(required=True, description="用户邮箱"),
        "password": fields.String(required=True, description="用户密码"),
    },
)

token_model = ns.model(
    "TokenResponse",  # 登录成功后返回的令牌模型
    {
        "access_token": fields.String(description="访问令牌"),
        "refresh_token": fields.String(description="刷新令牌"),
    },
)


# /**
#  * 作者: "test_LH"
#  * 日期: 2025-10-11
#  * 名称: LoginResource
#  * 作用: 处理用户登录请求并返回访问与刷新令牌
#  * 参数:
#  *   @param 无 类实例化由 Flask-RESTX 管理
#  * 返回: 无
#  * 备注: 基于邮箱与密码验证
#  */
@ns.route("/login")
class LoginResource(Resource):
    # /**
    #  * 作者: "test_LH"
    #  * 日期: 2025-10-11
    #  * 名称: post
    #  * 作用: 校验登录信息并签发访问令牌与刷新令牌
    #  * 参数:
    #  *   @param self 当前资源实例
    #  * 返回: 包含 access_token 与 refresh_token 的字典
    #  * 备注: 验证失败返回 401
    #  */
    @ns.expect(login_model, validate=True)
    @ns.marshal_with(token_model)
    def post(self):
        payload = ns.payload
        datastore = current_app.extensions["security"].datastore
        user = datastore.find_user(email=payload["email"].lower())
        if not user or not verify_password(payload["password"], user.password):
            ns.abort(401, "邮箱或密码错误")

        roles = [role.name for role in user.roles]
        access = create_access_token(identity=str(user.id), additional_claims={"roles": roles})
        refresh = create_refresh_token(identity=str(user.id))
        return {"access_token": access, "refresh_token": refresh}


refresh_model = ns.model(
    "RefreshResponse",  # 刷新 token 响应模型
    {
        "access_token": fields.String(description="新的访问令牌"),
    },
)


# /**
#  * 作者: "test_LH"
#  * 日期: 2025-10-11
#  * 名称: TokenRefreshResource
#  * 作用: 为合法刷新令牌签发新的访问令牌
#  * 参数:
#  *   @param 无 类实例化由 Flask-RESTX 管理
#  * 返回: 无
#  * 备注: 需要 refresh token 身份
#  */
@ns.route("/refresh")
class TokenRefreshResource(Resource):
    # /**
    #  * 作者: "test_LH"
    #  * 日期: 2025-10-11
    #  * 名称: post
    #  * 作用: 校验刷新令牌并生成新的访问令牌
    #  * 参数:
    #  *   @param self 当前资源实例
    #  * 返回: 包含新的 access_token 的字典
    #  * 备注: 用户不存在时返回 404
    #  */
    @jwt_required(refresh=True)
    @ns.marshal_with(refresh_model)
    def post(self):
        identity = get_jwt_identity()
        datastore = current_app.extensions["security"].datastore
        user = datastore.find_user(id=int(identity))
        if not user:
            ns.abort(404, "用户不存在")
        roles = [role.name for role in user.roles]
        access = create_access_token(identity=str(user.id), additional_claims={"roles": roles})
        return {"access_token": access}


user_model = ns.model(
    "CurrentUser",  # 当前登录用户响应模型
    {
        "id": fields.Integer,
        "email": fields.String,
        "roles": fields.List(fields.String),
    },
)


# /**
#  * 作者: "test_LH"
#  * 日期: 2025-10-11
#  * 名称: CurrentUserResource
#  * 作用: 返回当前登录用户的基础信息与角色列表
#  * 参数:
#  *   @param 无 类实例化由 Flask-RESTX 管理
#  * 返回: 无
#  * 备注: 需要有效访问令牌
#  */
@ns.route("/me")
class CurrentUserResource(Resource):
    # /**
    #  * 作者: "test_LH"
    #  * 日期: 2025-10-11
    #  * 名称: get
    #  * 作用: 查询当前身份对应的用户详情并返回
    #  * 参数:
    #  *   @param self 当前资源实例
    #  * 返回: 包含用户 ID、邮箱及角色列表的字典
    #  * 备注: 用户不存在时返回 404
    #  */
    @jwt_required()
    @ns.marshal_with(user_model)
    def get(self):
        identity = get_jwt_identity()
        user = User.query.get(int(identity))
        if not user:
            ns.abort(404, "用户不存在")
        return {
            "id": user.id,
            "email": user.email,
            "roles": [role.name for role in user.roles],
        }
